from animation import *
import g
import pygame
from gameobject import GameObject

class Character(GameObject):
	allDirections = ["U", "UF", "F", "DF", "D", "DB", "B", "UB"]
	allAttacks = ["lP", "mP", "hP", "lK", "mK", "hK"]
	floor = 200
	def __init__(self, frames):
		GameObject.__init__(self, frames[0], self, 200, 200)
		self.animations = { }
		self.anim = None
		self.lastAnim = None
		self.center = (184, 119)
		self.xVelocity = 0
		self.yVelocity = 0
		self.t = 0
		self.client = False
		self.server = False
		self.groundSlideVelocity = 0
		self.changeAnimationTo = None
		self.parryingTimer = None
		self.directionKeys = {}
		self.bindings = {}
		self.buttonsDown = {}
		self.buttonsJustPressed = {}
		self.buttonsJustReleased = {}
		self.buttonHistory = []
		self.joystickDirection = ""
		self.inAir = False
		self.debugName = ""
		self.owner = None
		self.health = 1000
		self.maxHealth = 1000
		self.floating = False
		self.name = "Character"
		self.cannotMoveBack = False
		self.knockedDown = False

	def hit(self, other):
		pass

	def blockKnockback(self):
		self.groundSlideVelocity = (-10, 10)[self.facing == "LEFT"]

	def getHit(self, other, box):
		if other.owner == self:
			return
		if self.anim.name == "knockdown":
			return

		if self.parryingTimer is not None:
			self.play("parry")
		elif self.joystickDirection == "DB" and (self.anim.canExit or "block" in self.anim.name):
			self.play("crouchblock", True, True)
			other.blockKnockback()
			self.health -= 10
		elif self.joystickDirection == "B" and (self.anim.canExit or "block" in self.anim.name):
			self.play("block", True, True)
			other.blockKnockback()
			self.health -= 10
		else:
			if "damage" in box.properties:
				if self.server:
					self.health -= int(box.properties["damage"])
			
			slide = 4.0
			if "knockback" in box.properties:
				slide = float(box.properties["knockback"])
			self.groundSlideVelocity = (-slide, slide)[self.facing == "LEFT"]
			
			if "knockup" in box.properties:
				self.inAir = True
				self.yVelocity = -float(box.properties["knockup"])
				xv = float(box.properties["knockup"]) / 5
				self.xVelocity = (-xv, xv)[self.facing == "LEFT"]
				self.play("getairhit", True, True)
				self.knockedDown = True
			else:
				self.play("gethit", True, True)

	def initialize(self):
		self.play("idle", net = True)
		allButtons = self.allAttacks[::]
		allButtons.extend(self.allDirections)
		for button in allButtons:
			self.buttonsDown[button] = False
			self.buttonsJustPressed[button] = False
			self.buttonsJustReleased[button] = False

	def play(self, animName, nextFrame = False, force = False, net = False):
		if not net and not self.server:
			return
		if self.anim != self.animations[animName] or force:
			if nextFrame:
				self.changeAnimationTo = animName
			else:
				self.lastAnim = self.anim
				self.anim = self.animations[animName]
				self.anim.start()
				self.attackAlreadyHit = False

	def updateAnimation(self):
		if self.changeAnimationTo is not None:
			self.lastAnim = self.anim
			self.anim = self.animations[self.changeAnimationTo]
			self.anim.start()
			self.changeAnimationTo = None
			self.attackAlreadyHit = False
		self.anim.update()

	def clearOldInput(self):
		if(len(self.buttonHistory) > 20):
			self.buttonHistory = self.buttonHistory[-20:]
		allButtons = self.allAttacks[::]
		allButtons.extend(self.allDirections)
		for button in allButtons:
			if self.buttonsJustPressed[button]:
				print(str(self.t) + ": " + button)
				self.buttonHistory.append(button)
			self.buttonsJustPressed[button] = False
			self.buttonsJustReleased[button] = False

	def updateClientInput(self):
		if not self.client:
			return

		keys = pygame.key.get_pressed()
		xd = ""
		yd = ""
		if keys[self.directionKeys["U"]]:
			yd = "U"
		elif keys[self.directionKeys["D"]]:
			yd = "D"
		if keys[self.directionKeys["L"]]:
			if self.facing == "LEFT":
				xd = "F"
			else:
				xd = "B"
		elif keys[self.directionKeys["R"]]:
			if self.facing == "LEFT":
				xd = "B"
			else:
				xd = "F"

		oldDirection = self.joystickDirection
		self.joystickDirection = yd + xd
		if oldDirection != self.joystickDirection:
			if self.joystickDirection != "":
				self.buttonsJustPressed[self.joystickDirection] = True
				#if self.joystickDirection == "F":
					#self.parryingTimer = 3
			if oldDirection == "":
				self.buttonsJustReleased[oldDirection] = True

			g.gGame.netClient.sendJoystick(self.joystickDirection)

	def setFacing(self, facing):
		if not self.inAir:
			self.facing = facing

	def update(self, shouldUpdateAnimation):
		self.t += 1
		
		self.x += self.groundSlideVelocity
		self.groundSlideVelocity *= 0.65

		if self.parryingTimer is not None:
			self.parryingTimer -= 1
			if self.parryingTimer <= 0:
				self.parryingTimer = None

		self.floating = False

		if shouldUpdateAnimation:
			self.updateAnimation()

		special = self.specialInput()
		if special:
			if self.anim.canExit:
				self.play(special)
			cancelsIntoSpecial = self.anim.cancelsInto.get("special", [])
			if self.anim.getFrame() in cancelsIntoSpecial:
				if self.server:
					g.gGame.showDebugText(self.anim.name + " cancel into " + special, self.x, self.y - 50)
				self.play(special)

		attack = self.attackInput()
		if attack:
			if self.anim.canExit:
				self.play(attack)
			cancelsIntoFrames = self.anim.cancelsInto.get(attack,[])
			if self.anim.getFrame() in cancelsIntoFrames:
				if self.server:
					g.gGame.showDebugText(self.anim.name + " chain into " + attack, self.x, self.y - 50)
				self.play(attack)

		self.updateSpecials()

		if self.anim.ended:
			self.doMovement()

		if self.inAir or self.floating:
			self.y = int(self.y + self.yVelocity)
			self.x += self.xVelocity
			if not self.floating:
				self.yVelocity += 0.5
				if self.y >= self.floor:
					self.y = self.floor
					self.inAir = False
					self.xVelocity = 0
					if self.knockedDown:
						self.play("knockdown")
						self.knockedDown = False
					else:
						self.play("idle")

		self.clearOldInput()
		self.updateClientInput()

	def updateSpecials(self):
		pass

	def attackInput(self):
		if self.inAir:
			if self.buttonsJustPressed["lP"]:
				return "j.lP"
			if self.buttonsJustPressed["mP"]:
				if self.xVelocity == 0:
					return "j.mP2"
				else:
					return "j.mP"
			if self.buttonsJustPressed["hP"]:
				return "j.hP"
			if self.buttonsJustPressed["lK"]:
				return "j.lK"
			if self.buttonsJustPressed["mK"]:
				return "j.mK"
			if self.buttonsJustPressed["hK"]:
				return "j.hK"
		elif "D" in self.joystickDirection:
			if self.buttonsJustPressed["lP"]:
				return "c.lP"
			if self.buttonsJustPressed["mP"]:
				return "c.mP"
			if self.buttonsJustPressed["hP"]:
				return "c.hP"
			if self.buttonsJustPressed["lK"]:
				return "c.lK"
			if self.buttonsJustPressed["mK"]:
				return "c.mK"
			if self.buttonsJustPressed["hK"]:
				return "c.hK"
		else:
			if self.buttonsJustPressed["lP"]:
				return "lP"
			if self.buttonsJustPressed["mP"]:
				return "mP"
			if self.buttonsJustPressed["hP"]:
				return "hP"
			if self.buttonsJustPressed["lK"]:
				return "lK"
			if self.buttonsJustPressed["mK"]:
				return "mK"
			if self.buttonsJustPressed["hK"]:
				return "hK"

	def doMovement(self):
		if self.joystickDirection == "F":
			self.play("walkf")
			self.x += (3, -3)[self.facing == "LEFT"]
		elif self.joystickDirection == "B" and not self.cannotMoveBack:
			self.play("walkb")
			self.x += (-2, 2)[self.facing == "LEFT"]
		elif self.joystickDirection == "D" or self.joystickDirection == "DF" or self.joystickDirection == "DB":
			self.play("crouch")
		elif not self.inAir and self.buttonsJustPressed["U"]:
			self.play("jump")
			self.yVelocity = -10
			self.inAir = True
		elif not self.inAir and self.buttonsJustPressed["UF"]:
			self.play("jumpf")
			self.yVelocity = -10
			self.xVelocity = (3, -3)[self.facing == "LEFT"]
			self.inAir = True
		elif not self.inAir and self.buttonsJustPressed["UB"]:
			self.play("jumpb")
			self.yVelocity = -10
			self.xVelocity = (-3, 3)[self.facing == "LEFT"]
			self.inAir = True
		elif self.joystickDirection == "":
			self.play("idle")
			
	def specialInput(self):
		pass

	def keyPress(self, key):
		if not self.client:
			return
		if key in self.bindings:
			self.buttonsDown[self.bindings[key]] = True
			self.buttonsJustPressed[self.bindings[key]] = True

			g.gGame.netClient.sendButton(self.bindings[key])

	def buttonRelease(self, key):
		if key in self.bindings:
			self.buttonsDown[self.bindings[key]] = False
			self.buttonsJustReleased[self.bindings[key]] = True

	def render(self, screen, scroll):
		frame = self.anim.getFrame()
		if self.facing == "RIGHT":
			frame = pygame.transform.flip(frame, True, False)
		screen.blit(frame, (self.x - self.center[0] - scroll[0], self.y - self.center[1] - scroll[1]))

	def renderHitbox(self, screen, scroll):
		for box in self.getAbsBoxFrame():
			if box.properties["type"] == 0:
				boxTypeColor = (0, 0, 255)
			else:
				boxTypeColor = (255, 0, 0)
			rect = (box.rect[0] - scroll[0], box.rect[1] - scroll[1], box.rect[2], box.rect[3])
			pygame.draw.rect(screen, boxTypeColor, rect, 1)

	def getAbsBoxFrame(self):
		absBoxes = []
		for box in self.anim.getHitboxFrame():
			if self.facing == "LEFT":
				newBox = Hitbox(box.getOffsetRect((self.x, self.y), False), box.properties)
			else:
				newBox = Hitbox(box.getOffsetRect((self.x, self.y), True), box.properties)
			absBoxes.append(newBox)
		return absBoxes

class Ken(Character):
	def __init__(self, frames):
		Character.__init__(self, frames)
		self.animations = {
			"idle" : LoopingAnimation(frames[0:9]),
			"walkf" : LoopingAnimation(frames[13:24]),
			"walkb" : LoopingAnimation(frames[25:35]),
			"crouch" : LoopingAnimation([frames[43]] * 3 + [frames[44]] * 3 + [frames[45]] * 3 + [frames[46]] * 3),
			"lP" : Animation(frames[288:292]),
			"mP" :Animation(frames[293:299], {"hP":frames[297:299]}),
			"hP" : Animation(frames[300:310], {"special":frames[304:310]}),
			"lK" : Animation(frames[353:359]),
			"mK" : Animation(frames[345:352] + frames[390:393]),
			"hK" : Animation(frames[381:393]),
			"c.lP" : Animation(frames[394:397]),
			"c.mP" : Animation(frames[397:398] + frames[395:397]),
			"c.hP" : Animation(frames[399:407]),
			"c.lK" : Animation(frames[408:413]),
			"c.mK" : Animation(frames[414:419], {"special":frames[416:419]}),
			"c.hK" : Animation(frames[420:429]),
			"jump" : JumpAnimation(frames[51:62]),
			"jumpb" : JumpAnimation([frames[63]] + frames[72:64:-1] + frames[73:74]),
			"jumpf" : JumpAnimation(frames[63:75]),
			"j.lP" : Animation(frames[430:435]),
			"j.mP" : Animation(frames[436:443]),
			"j.mP2" : Animation(frames[445:452]),
			"j.hP" : Animation(frames[436:441] + [frames[444]] + frames[442:443]),
			"j.lK" : Animation(frames[459:460] + frames[454:458]),
			"j.mK" : Animation(frames[459:460] + frames[461:466]),
			"j.hK" : Animation(frames[473:478]),
			"gethit" : Animation(frames[121:122] + frames[130:135]),
			"getairhit" : Animation(frames[182:189] + [frames[189]] * 10),
			"parry" : ParryAnimation(frames[311:315]),
			"lP shuryuken" : Animation(frames[516:529]),
			"mP shuryuken" : Animation(frames[516:529]),
			"hP shuryuken" : Animation(frames[516:529]),
			"lP hadouken" : Animation(frames[502:512]),
			"lK tatsumaki" : Animation(frames[530:533] + frames[575:580]),
			"mK tatsumaki" : Animation(frames[530:533] + frames[575:580] * 2),
			"hK tatsumaki" : Animation(frames[530:533] + frames[575:580] * 4),
			"knockdown" : Animation(frames[190:209] + frames[265:275]),
			"block" : Animation([frames[77]] + frames[82:85]),
			"crouchblock" : Animation(frames[86:90]),
		}
		for k,v in self.animations.items():
			v.name = k

		self.madeProjectile = False

		self.play("idle")

	def specialInput(self):
		if self.buttonHistory[-3:] == ["F", "D", "DF"]:
			if self.buttonsJustPressed["lP"]:
				return "lP shuryuken"
			elif self.buttonsJustPressed["mP"]:
				return "mP shuryuken"
			elif self.buttonsJustPressed["hP"]:
				return "hP shuryuken"
		if self.buttonHistory[-3:] == ["D", "DF", "F"]:
			if self.buttonsJustPressed["lP"]:
				return "lP hadouken"
					
		if self.buttonHistory[-3:] == ["D", "DB", "B"]:
			if self.buttonsJustPressed["lK"]:
				return "lK tatsumaki"
			elif self.buttonsJustPressed["mK"]:
				return "mK tatsumaki"
			elif self.buttonsJustPressed["hK"]:
				return "hK tatsumaki"

	def updateSpecials(self):
		if self.anim == self.animations["lP shuryuken"]:
			if self.anim.n == 4:
				self.yVelocity = -5
				self.inAir = True
				
		elif self.anim == self.animations["mP shuryuken"]:
			if self.anim.n > 3:
				if self.anim.n < 5:
					self.yVelocity = -8
				if self.anim.n < 6:
					self.xVelocity = (3, -3)[self.facing == "LEFT"]
				else:
					self.xVelocity = 0
				self.inAir = True

				
		elif self.anim == self.animations["hP shuryuken"]:
			if self.anim.n > 3:
				if self.anim.n < 5:
					self.yVelocity = -8
				if self.anim.n < 8:
					self.xVelocity = (5, -5)[self.facing == "LEFT"]
				else:
					self.xVelocity = 0
				self.inAir = True

		elif self.anim == self.animations["lP hadouken"]:
			if self.anim.n == 3 and not self.madeProjectile:
				self.madeProjectile = True
				if self.facing == "LEFT":
					px = self.x - 55
					xv = -6
				else:
					px = self.x + 55
					xv = 6
				g.gGame.createObject("hadouken", self, px, self.y, xv)

			if self.anim.n == 4:
				self.madeProjectile = False

		if self.anim == self.animations["lK tatsumaki"] or self.anim == self.animations["mK tatsumaki"] or self.anim == self.animations["hK tatsumaki"]:
			if self.anim.n > 1:
				if not self.inAir:
					self.floating = True
					self.yVelocity = 0
				self.xVelocity = (3, -3)[self.facing == "LEFT"]
			if ((self.anim.n - 3) % 5) == 0:
				self.attackAlreadyHit = False

allCharacters = {"ken": Ken}